type ValidatorRule = unknown
type ValidatorCallback = (error?: Error) => void
type ValidatorFunction = (rule: ValidatorRule, value: string, callback: ValidatorCallback) => void

interface ValidationRule {
  required?: boolean
  validator?: ValidatorFunction
  trigger?: string
  message?: string
  grade?: number
}

/**
 * Creates a required field validation rule
 * @param message - Error message (default: '此项必填')
 * @param trigger - Trigger event (default: 'blur')
 * @returns Validation rule object
 */
function required(message: string = '此项必填', trigger: string = 'blur'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^\s*$/g
    if (reg.test(value) || value === null || value === undefined || value === '') {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    required: true,
    validator,
    trigger,
    message,
  }
}

/**
 * Creates a number-only validation rule
 * @param message - Error message (default: '只能输入数字')
 * @returns Validation rule object
 */
function number(message: string = '只能输入数字'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const reg = /^[0-9]+$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a non-empty validation rule (no whitespace)
 * @param message - Error message (default: '不能为空')
 * @returns Validation rule object
 */
function space(message: string = '不能为空'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value.trim() === '') {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for numbers between 1-19
 * @param message - Error message (default: '只能输入数字且大小在1-19之间')
 * @returns Validation rule object
 */
function minNumber(message: string = '只能输入数字且大小在1-19之间'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const reg = /^([1-9]|1\d)$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for floating point numbers
 * @param message - Error message (default: '只能是数字')
 * @returns Validation rule object
 */
function double(message: string = '只能是数字'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /[0-9]+$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for numbers with max length of 5
 * @param message - Error message (default: '数字限制最大长度')
 * @returns Validation rule object
 */
function numberLim(message: string = '数字限制最大长度'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^[0-9]{0,5}$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for alphanumeric input
 * @param message - Error message (default: '只能输入英文或数字')
 * @returns Validation rule object
 */
function string(message: string = '只能输入英文或数字'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^[a-zA-Z0-9]+$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for lowercase alphanumeric input
 * @param message - Error message (default: '只能是小写字母和数字')
 * @returns Validation rule object
 */
function NumAndStr(message: string = '只能是小写字母和数字'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^[a-z0-9]+$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule to exclude Chinese characters
 * @param message - Error message (default: '不能含有汉字')
 * @returns Validation rule object
 */
function checkChinese(message: string = '不能含有汉字'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (!value) {
      callback()
      return
    }

    for (let i = 0; i < value.length; i++) {
      if (value.charCodeAt(i) > 255) {
        callback(new Error(message))
        return
      }
    }
    callback()
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for Chinese ID card numbers
 * @param message - Error message (default: '身份证格式不正确')
 * @returns Validation rule object
 */
function isCardNo(message: string = '身份证格式不正确'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for email addresses
 * @param message - Error message (default: '请输入正确的邮箱地址')
 * @returns Validation rule object
 */
function email(message: string = '请输入正确的邮箱地址'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'change',
  }
}

/**
 * Creates a validation rule for mobile phone numbers
 * @param message - Error message (default: '请输入正确的手机号')
 * @returns Validation rule object
 */
function mobile(message: string = '请输入正确的手机号'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^1\d{10}$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for telephone numbers
 * @param message - Error message (default: '请输入正确的固定电话')
 * @returns Validation rule object
 */
function tel(message: string = '请输入正确的固定电话'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const reg = /^0\d{2,3}-?\d{7,8}$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for email or mobile phone
 * @param message - Error message (default: '请输入正确的邮箱地址或手机号码')
 * @returns Validation rule object
 */
function emailOrMobile(message: string = '请输入正确的邮箱地址或手机号码'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/
    const regMobile = /^1\d{10}$/

    if (regEmail.test(value) || regMobile.test(value)) {
      callback()
    } else {
      callback(new Error(message))
    }
  }

  return {
    validator,
    trigger: 'change',
  }
}

/**
 * Creates a validation rule for mobile or telephone
 * @param message - Error message (default: '请输入正确的邮箱地址或手机号码')
 * @returns Validation rule object
 */
function mobileOrTel(message: string = '请输入正确的邮箱地址或手机号码'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    if (value === '') {
      callback()
      return
    }
    const regMobile = /^1\d{10}$/
    const regTel = /^0\d{2,3}-?\d{7,8}$/

    if (regMobile.test(value) || regTel.test(value)) {
      callback()
    } else {
      callback(new Error(message))
    }
  }

  return {
    validator,
    trigger: 'change',
  }
}

/**
 * Creates a validation rule for 6-digit verification codes
 * @param message - Error message (default: '请输入6位数字验证码')
 * @returns Validation rule object
 */
function verificationCode(message: string = '请输入6位数字验证码'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /\d{6}$/
    if (!reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a validation rule for URLs
 * @param message - Error message (default: 'URL格式不正确')
 * @returns Validation rule object
 */
function isURL(message: string = 'URL格式不正确'): ValidationRule {
  const validator: ValidatorFunction = (_rule, value, callback) => {
    const reg = /^(http:\/\/|https:\/\/|\/).*$/
    if (value.trim() !== '' && !reg.test(value)) {
      callback(new Error(message))
    } else {
      callback()
    }
  }

  return {
    validator,
    trigger: 'blur',
  }
}

/**
 * Creates a password strength validation rule
 * @param message - Error message (default: '您输入的密码不满足要求')
 * @returns Validation rule object with grade
 */
function pswd(message: string = '您输入的密码不满足要求'): ValidationRule & { grade?: number } {
  let grade: number | undefined

  const validator: ValidatorFunction = (_rule, value, callback) => {
    // Password must contain: digits, uppercase, lowercase, special chars, 8-16 chars
    const strongReg = /(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,16}/
    // Password must contain: digits, letters, special chars, 8-16 chars
    const mediumReg = /(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,16}/
    // Password must contain: digits and letters, 8-16 chars
    const weakReg = /(?=.*[0-9])(?=.*[a-zA-Z]).{8,16}/

    if (value === '' || value === undefined) {
      callback()
      return
    }

    if (strongReg.test(value)) {
      grade = 3
    } else if (mediumReg.test(value)) {
      grade = 2
    } else if (weakReg.test(value)) {
      grade = 1
    } else {
      grade = 0
      callback(new Error(message))
      return
    }

    callback()
  }

  return {
    validator,
    trigger: 'blur',
    grade,
  }
}

export default {
  required,
  number,
  space,
  minNumber,
  double,
  numberLim,
  string,
  NumAndStr,
  isCardNo,
  email,
  mobile,
  tel,
  emailOrMobile,
  mobileOrTel,
  verificationCode,
  checkChinese,
  isURL,
  pswd,
}
